//
//  BKUpgradeVC.swift
//  SDKDebuggingDemo
//
//  Created by 秦晟哲 on 2019/8/1.
//  Copyright © 2019 QinszQSZ. All rights reserved.
//

import UIKit

class BKUpgradeVC: UIViewController,KCTSingleBLEShellBKUpgradeDelegate {
    

    @IBOutlet weak var processView: UITextView!
    
    let bleShell = KCTSingleBLEShell.sharedInstance
    
    var firmware:KCTFirmwareInfos?

    /// 升级bin文件,拆分为16字节的数组
    var upgradeDataSerials = Array<Data>.init()
    /// 当前发送的包序号(upgradeDataSerials序号)
    var sendingIndex:Int = -1

    /// 发送upgradeDataSerials时使用
    var sendTimer:Timer?
    
    
    /// 最近的一次重发数据包序号
    var lastResendIndex:UInt16 = 0
    /// 同一序号被要求连续重发的次数,超过阈值，说明数据包或者设备端处理有错误，应终止发送loop
    var resendCount = 0
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        self.bleShell.bkUpgradeDelegate = self
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.bleShell.bkUpgradeDelegate = self
    }

    @IBAction func clickBack(_ sender: Any) {
        self.navigationController?.popViewController(animated: true)
    }
    
    
    //MARK: - Step01 获取固件信息
    @IBAction func clickStart(_ sender: Any) {
        
        SVProgressHUD.show(withStatus: "获取固件信息...")
        self.processView.text = nil
        let firmwareTask = KCTOldBLETaskReadFirmwareInfos.init {[weak self] (tsk, error, infosModel) in
            if let err = error{
                SVProgressHUD.showError(withStatus: "获取固件信息失败")
                self?.processView.text = "获取固件信息失败:" + err.description
            }else{
                if let model = infosModel {
                    
                    if model.platform == 4 {
                        self?.firmware = model
                        
                        //向服务器请求固件资源信息
                        self?.requestFirmwareVersionInfos()
                    }else{
                        SVProgressHUD.showError(withStatus: "固件平台错误")
                        self?.processView.text = "固件平台错误:\(model.platform)"
                    }
                }else {
                    SVProgressHUD.showError(withStatus: "获取固件信息失败")
                    self?.processView.text = "获取固件信息失败: firmware为空"
                }
            }
        }
        bleShell.resume(baseTask: firmwareTask)
    }
    
    
    //MARK: - Step_02 获取固件升级资源包版本信息
    func requestFirmwareVersionInfos() {
        
        SVProgressHUD.show(withStatus: "获取固件版本...")
        
        guard let serialsNum = self.firmware?.serialNumber  else {
            SVProgressHUD.showError(withStatus: "请求升级包缺少固件信息")
            IPrint("请求升级包缺少固件信息")
            self.processView.text = "请求升级包缺少固件信息"
            self._clearTempInfos()
            return
        }
        
        let versionTask = KCTHTTPSession.share.FirmwareInfoTask(fromProduct: false, appKey: TestAPPKey, secretKey: TestSecretKey, adaptiveNum: serialsNum) {[weak self] (infos, error) in
            
            DispatchQueue.main.async {
                
                if let err = error {
                    IPrint("\(err)\n")
                    self?.processView.text = err.description
                    SVProgressHUD.showError(withStatus: err.description)
                    self?._clearTempInfos()
                    return
                }
                
                
                guard let `infos` = infos else{
                    // 没有固件信息
                    IPrint("线上没有固件信息（适配号=\(serialsNum)）")
                    SVProgressHUD.dismiss()
                    self?.processView.text = "线上没有固件信息（适配号=\(serialsNum)）"
                    self?._clearTempInfos()
                    return
                }
                
                //请求资源包
                self?.requestFirmwareFile(fileUrl: infos.file)
            }
        }
        versionTask?.resume()
        
    }
    
    
    //MARK: - Step_03 获取固件升级资源文件
    func requestFirmwareFile(fileUrl:String){
        
        SVProgressHUD.show(withStatus: "获取固件升级文件...")
        if let url = URL.init(string: fileUrl){
            let request = URLRequest.init(url: url)
            let session = URLSession.shared
            let task = session.dataTask(with: request) {[weak self] (data, rsp, error) in
                DispatchQueue.main.sync {
                    
                    if let `data` = data{
                        if let mimeType = rsp?.mimeType?.contains("zip"), mimeType == true {

                            //解压zip包，获取里面的bin文件
                            
                            let d = NSData.init(data: data)
                            let zipPath = (self?._zipFolder())! + "/tempBK.zip"
                            let _ = d.write(toFile: zipPath, atomically: false)
                            
                            let folderPath = (self?._zipFolder())! + "/bk"
                            let unzipSuc = SSZipArchive.unzipFile(atPath: zipPath, toDestination: folderPath)
                            
                            if unzipSuc {
                                
                                let paths = FileManager.default.subpaths(atPath: folderPath)
                                
                                var binPath:String?
                                
                                if let ps = paths {
                                    for filePath in ps {
                                        let p = NSString.init(string: filePath)
                                        if p.hasSuffix("bin"){
                                            binPath = filePath
                                            break
                                        }
                                    }
                                }
                                
                                if let binP = binPath {
                                    let path = folderPath + "/" + binP
                                    let binData = NSData.init(contentsOfFile: path)!
                                    
                                    
                                    //拆分为Data数组，16字节一组
                                    self?.upgradeDataSerials = (self?._splitData(data: Data.init(referencing: binData), upperlimit: 16))!
                                    
                                    //尝试擦除flash
                                    self?.clearFlash()
                                }else{
                                    let errInfos = "没有找到bin文件"
                                    SVProgressHUD.showError(withStatus: errInfos)
                                    IPrint("\(errInfos)\n")
                                    self?.processView.text = errInfos
                                    self?._clearTempInfos()
                                }
                                
                            }else{
                                let errInfos = "解压zip包失败"
                                SVProgressHUD.showError(withStatus: errInfos)
                                IPrint("\(errInfos)\n")
                                self?.processView.text = errInfos
                                self?._clearTempInfos()
                            }
                            
                        }else{
                            let errInfos = "mimeType不含zip，mimeType=\(rsp?.mimeType ?? "为空")"
                            SVProgressHUD.showError(withStatus: errInfos)
                            IPrint("\(errInfos)\n")
                            self?.processView.text = errInfos
                            self?._clearTempInfos()
                        }
                    }else{
                        let errInfos = "获取固件升级文件失败"
                        SVProgressHUD.showError(withStatus: errInfos)
                        IPrint("\(errInfos)\n")
                        self?.processView.text = errInfos
                        self?._clearTempInfos()
                    }
                    
                    
                }
            }
            task.resume()
        }else{
            let errInfos = "初始化固件地址URL错误:urlstr = \(fileUrl)"
            SVProgressHUD.showError(withStatus: errInfos)
            IPrint("\(errInfos)\n")
            self.processView.text = errInfos
            self._clearTempInfos()
        }
    }


    
    //MAKR: - Step04升级前尝试清除flash
    func clearFlash() {
        //尝试擦除flash
        SVProgressHUD.show(withStatus: "擦除flash...")
        let task = KCTOldBLETaskClearFlash.init {[weak self] (error, hasRsp,success) in
            if let err = error {
                let errInfos = "擦除flash失败:\(err.description)"
                IPrint("\(errInfos)\n")
                SVProgressHUD.showError(withStatus: errInfos)
                self?.processView.text = errInfos
                self?._clearTempInfos()
            }else{

                if hasRsp == false || (hasRsp == true && success == true){
                    if let header = self?.upgradeDataSerials.first{
                        IPrint("通道01发送header数据!\n")
                        // 发送成功后，设备会通过bkUpgradeChar02返回一个包序号（0000），从该序号开始，通过定时器分包发送bin文件
                        // 后续的bin文件用bkUpgradeChar02发送
                        if self?.bleShell.hasBK01 == true{
                            self?.bleShell.writeValueForBKUpgradeCharacteristic_01(value: header, type: .withoutResponse)
                        }else{
                            let errInfos = "没有bk01通道"
                            IPrint("\(errInfos)\n")
                            SVProgressHUD.showError(withStatus: errInfos)
                            self?.processView.text = errInfos
                            self?._clearTempInfos()
                        }
                    }else{
                        let errInfos = "缺少文件头"
                        IPrint("\(errInfos)\n")
                        SVProgressHUD.showError(withStatus: errInfos)
                        self?.processView.text = errInfos
                        self?._clearTempInfos()
                    }
                }else{
                    //擦除失败
                    let errInfos = "擦除flash失败:hasRsp=\(hasRsp),success=\(success)"
                    IPrint("\(errInfos)\n")
                    SVProgressHUD.showError(withStatus: errInfos)
                    self?.processView.text = errInfos
                    self?._clearTempInfos()
                }
            }
        }
        bleShell.resume(baseTask: task)
    }
    
    
    //MARK: - BK升级代理
    //通道01收到数据
    func singleBLEShell(shell: KCTSingleBLEShell, bkUpgradeCharacteristic01ReceivedRawData rawData: Data) {
        IPrint("BK通道01收到数据:\(NSData.init(data: rawData))\n")
    }
    //MARK:- step_05 开始发送数据包/重发数据包
    //通道02收到数据
    func singleBLEShell(shell: KCTSingleBLEShell, bkUpgradeCharacteristic02ReceivedRawData rawData: Data) {
        IPrint("BK通道02收到数据:\(NSData.init(data: rawData))\n")
        if rawData.count == 2 {
            let data = NSData.init(data: rawData)
            var value:UInt16 = 0
            data.getBytes(&value, range: NSMakeRange(0, 2))
            
            if lastResendIndex == value {
                resendCount = resendCount + 1
            }else{
                resendCount = 1
            }
            lastResendIndex = value
            
            if resendCount > 10 {
                //同一数据包被连续重发10次，说明数据包有问题或者设备处理有问题，应终止发送循环
                self.sendTimer?.invalidate()
                self.sendTimer = nil
                SVProgressHUD.showError(withStatus: "数据包序列可能有误")
                let errInfos = "终止发送，连续重发序号:\(value),重发次数:\(resendCount)"
                self.processView.text = errInfos
                self._clearTempInfos()
            }else{
                //
                IPrint("重新发送,序号（\(value))")
                self.sendTimer?.invalidate()
                self.sendingIndex = Int(value)
                startLoopSending()
            }
        }
    }
    
    func startLoopSending() {
        self.sendTimer?.invalidate()
        self.sendTimer = Timer.init(timeInterval: 0.05, target: self, selector: #selector(sendingLoop(timer:)), userInfo: nil, repeats: true)
        RunLoop.main.add(sendTimer!, forMode: .default)
    }

    @objc func sendingLoop(timer:Timer){
        
        if timer === self.sendTimer {
            if sendingIndex < upgradeDataSerials.count {
                SVProgressHUD.show(withStatus: "\(sendingIndex)/\(upgradeDataSerials.count)")
                //需要在数据包前拼接序列号,包序号用的小端
                var order = UInt16(sendingIndex)
                var orderedData = Data.init(bytes: &order, count: 2)
                orderedData.append(upgradeDataSerials[sendingIndex])
                if bleShell.hasBK02 {
                    IPrint("BK发送数据:\(NSData.init(data: orderedData))")
                    bleShell.writeValueForBKUpgradeCharacteristic_02(value: orderedData,type: .withoutResponse)
                    sendingIndex = sendingIndex + 1
                }else{
                    //特征丢失了（连接断开导致）
                    timer.invalidate()
                    self.sendTimer = nil
                    SVProgressHUD.showError(withStatus: "发送失败")
                    self._clearTempInfos()
                }
            }else if sendingIndex < 0{
                SVProgressHUD.showError(withStatus: "异常:sendIndex=\(sendingIndex)")
                timer.invalidate()
                self.sendTimer = nil
                self._clearTempInfos()
            }else{
                //发送完毕了
                SVProgressHUD.showSuccess(withStatus: "发送完毕")
                timer.invalidate()
                self.sendTimer = nil
                self._clearTempInfos()
            }
        }else{
            IPrint("其它timer")
            timer.invalidate()
        }
        
    
    }
    
    
    private func _clearTempInfos(){
        firmware = nil
        upgradeDataSerials.removeAll()
        if sendTimer != nil {
            sendTimer?.invalidate()
        }
        sendTimer = nil
        resendCount = 0
        lastResendIndex = 0
    }
    
    
    private func _zipFolder() -> String{
        
        let path = NSTemporaryDirectory() + "Zips"
        var isDir:ObjCBool = ObjCBool(false)
        let exists = FileManager.default.fileExists(atPath: path, isDirectory: &isDir)

        if exists == false || (exists == true && isDir.boolValue == false) {
            //创建路径
            try? FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
        }
        return path
    }
    
    
    public func _splitData(data:Data,upperlimit:Int) -> Array<Data> {
        if upperlimit <= 0{
            return [data]
        }else{
            var dataArray = Array<Data>.init()
            var restData = data
            while restData.count > upperlimit {
                let range = Range.init(NSMakeRange(0, upperlimit))!
                let sliceData = restData.subdata(in: range)
                dataArray.append(sliceData)
                let restRange = Range.init(NSMakeRange(sliceData.count, restData.count - sliceData.count))!
                restData = restData.subdata(in: restRange)
            }
            
            dataArray.append(restData)
            
            return dataArray
        }
    }

}
